package xyz.bali16.module.netdisk.controller;

import cn.hutool.core.collection.CollectionUtil;
import com.baomidou.mybatisplus.core.conditions.Wrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.io.IOUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.MediaType;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import xyz.bali16.application.core.enums.ApiEnum;
import xyz.bali16.application.core.exception.BusinessException;
import xyz.bali16.application.core.model.Result;
import xyz.bali16.application.core.utils.AuthUtils;
import xyz.bali16.application.core.utils.IDUtils;
import xyz.bali16.module.netdisk.utils.PageUtils;
import xyz.bali16.application.core.utils.TimeUtil;
import xyz.bali16.application.entity.User;
import xyz.bali16.module.netdisk.entity.*;
import xyz.bali16.module.netdisk.model.vo.FileFolderFileVoConvert;
import xyz.bali16.module.netdisk.model.vo.FileVo;
import xyz.bali16.module.netdisk.model.vo.UploadFileFileVoConvert;
import xyz.bali16.module.netdisk.service.FileFolderService;
import xyz.bali16.module.netdisk.service.FileUserService;
import xyz.bali16.module.netdisk.service.NetdiskService;
import xyz.bali16.module.netdisk.utils.BrowserUtil;
import xyz.bali16.module.netdisk.utils.FtpUtil;
import xyz.bali16.module.netdisk.utils.QRCodeUtil;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.validation.constraints.NotNull;
import java.io.*;
import java.net.URLEncoder;
import java.nio.file.Paths;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import static xyz.bali16.application.core.model.Result.failure;
import static xyz.bali16.application.core.model.Result.success;


@RestController
@RequestMapping(BaseController.API + "netdisk")
public class NetdiskController extends NetdiskBaseController {
    @Autowired
    NetdiskService netdiskService;

    @Value("${uploadfile.expired-time}")
    private Integer fileExpiredTime;

    @Resource
    private RedisTemplate<String, String> redisTemplate;


    boolean isRootDir(String id) {
        return id == "0";
    }

    boolean existSuffix(Integer index) {
        return index != -1;
    }

    boolean existFiles(List l) {
        return l.size() > 0;
    }

    boolean existFolders(List l) {
        return l.size() > 0;
    }

    @GetMapping("/files")
    @ApiOperation("后台访问文件接口")
    //@PreAuthorize("@auth.permission('plugin:netdisk:files')")
    public Result<Map<String, Object>> toFileStoragePage(@RequestParam(value = "fileStorageId", required = false) String fileStorageId,
                                                         @RequestParam(value = "fileFolderId", required = false) String fileFolderId,
                                                         @RequestParam(value = "fileUserId", required = false) String fileUserId) {
        Map<String, Object> map = new HashMap<>();
        //仓库ID -> 指定文件仓库
        //目录ID -> 查找当前目录下的所有文件

        //文件id
        //包含的子文件夹
        List<FileFolder> folders = null;
        //包含的文件
        List<UploadFile> files = null;
        //当前文件夹信息
        FileFolder currentFileFolder = null;
        //当前文件夹的相对路径
        List<FileFolder> location = new ArrayList<>();
        if (fileStorageId == null) {  // 如果不提供文件仓库Id，则使用当前用户默认的文件仓库id
            fileStorageId = fileUser.getFileStorageId();
            System.out.println("fileStorageId - null" + fileUser.toString());
        }

        FileStorage currentFileStorage = fileStorageService.getById(fileStorageId);
        if (fileFolderId == null || fileFolderId.equals("0")) { // 如果不提供文件夹Id,则使用当前用户默认的文件夹id（根目录）
            fileFolderId = "0"; //每个仓库的root目录都为0
            //这种设计就显得愚蠢， 两次查表，时间、空间都不是最好的。
            folders = fileFolderService.getRootFoldersByFileStorageId(fileStorageId);
            files = uploadFileService.getRootFilesByFileStorageId(fileStorageId);
            currentFileFolder = FileFolder.builder().name("根目录").id(fileFolderId).parentFolderId(fileFolderId).build();
        } else {
            // 当前为具体目录,访问的文件夹不是当前登录用户所创建的文件夹
            FileFolder folder = fileFolderService.getById(fileFolderId);
            if (!folder.getFileStorageId().equals(fileStorageId)) { // 访问的前提需要文件夹的文件仓库对应的上指定的文件仓库才行
                return failure();
            }
            // 当前为具体目录，访问的文件夹是当前登录用户所创建的文件夹
            folders = fileFolderService.getFileFoldersByParentFolderId(fileFolderId);
            files = uploadFileService.getFilesByParentFolderId(fileFolderId);
            currentFileFolder = fileFolderService.getById(fileFolderId);

            FileFolder temp = currentFileFolder;
            //todo 不断的查父级目录是谁,这个操作交给数据库递归查询按数组返回更高效率
            while (!temp.getParentFolderId().equals(temp.getId())) {
                temp = fileFolderService.getById(temp.getParentFolderId());
                location.add(temp);
            }
        }
        Collections.reverse(location);
        FileStorageStatistics statistics = uploadFileService.getCountStatistics(fileStorageId);
        map.put("statistics", statistics);
        if (fileUserId == null) {
            fileUserId = fileUser.getId();
        }
        System.out.println("currentFileFolder:" + currentFileFolder);
        FileUser currentFileUser = fileUserService.getById(fileUserId);
        if (fileUserId.equals("0")) {
            map.put("permission", fileStorageService.getById(fileStorageId).getPermission());
        } else {
            map.put("permission", fileStorageService.getFileStorageByFileUserId(fileUserId, fileStorageId).getPermission());
        }
        map.put("folders", folders);
        map.put("files", files);
        map.put("currentFileFolder", currentFileFolder);
        map.put("currentFileStorage", currentFileStorage);
        map.put("currentFileUser", currentFileUser);
        map.put("location", location);
        //logger.info("网盘页面域中的数据:" + map);
        return success(map);
    }

    public PageUtils listFiles(String fileStorageId, String fileFolderId,
                               @RequestParam(value = "curPage", required = false, defaultValue = "1") Integer curPage,
                               @RequestParam(value = "pageSize", required = false, defaultValue = "20") Integer pageSize) {
        List<FileFolder> folders = null;
        //包含的文件
        List<UploadFile> files = null;
        // 如果指定了要访问的文件夹
        if (fileFolderId != null) {
//            FileFolder filefolder = fileFolderService.getById(fileFolderId);
//            if(filefolder.getParentFolderId().equals(fileFolderId)){
            folders = fileFolderService.getFileFoldersByParentFolderId(fileFolderId);
            files = uploadFileService.getFilesByParentFolderId(fileFolderId);
            folders = folders.stream().filter(f -> !f.getId().equals(fileFolderId)).collect(Collectors.toList());
//            }
        } else { // 没有指定要访问的文件夹，就以列出文件仓库里的文件就可以了
            folders = fileFolderService.getRootFoldersByFileStorageId(fileStorageId);
            files = uploadFileService.getRootFilesByFileStorageId(fileStorageId);
        }
//        else if (fileFolderId == null || fileFolderId <= 0) { //
//            folders = fileFolderService.getRootFoldersByFileStorageId(fileStorageId);
//            files = uploadFileService.getRootFilesByFileStorageId(fileStorageId);
//        } else {
//            folders = fileFolderService.getFileFoldersByParentFolderId(fileFolderId);
//            files = uploadFileService.getFilesByParentFolderId(fileFolderId);
//        }

        List<FileVo> genericFiles = new ArrayList<>();
        if (CollectionUtil.isNotEmpty(folders)) {
            genericFiles.addAll(FileFolderFileVoConvert.INSTANCE.map(folders));
        }
        if (CollectionUtil.isNotEmpty(files)) {
            genericFiles.addAll(UploadFileFileVoConvert.INSTANCE.map(files));
        }

        System.out.println(folders);
        System.out.println("files:");
        System.out.println(files);
        System.out.println(genericFiles);
        Integer skipCount = (curPage - 1) * pageSize;
        Integer totalCount = genericFiles.size(); //获取过滤前总量,让前端知道多少页
        //因为一开始设计问题，导致现在要手动在java逻辑层实现分页
        List<FileVo> sortFiles = genericFiles.stream().sorted(Comparator.comparing(FileVo::getSize).reversed().thenComparing(FileVo::getGmtCreated).reversed()).skip(skipCount).limit(pageSize).collect(Collectors.toList());
        System.out.println("sortFiles");
        System.out.println(sortFiles);
        PageUtils pages = new PageUtils(curPage, pageSize, totalCount, sortFiles);
        return pages;
    }

    @GetMapping("/listByUserId")
    @ApiOperation("根据用户列出网盘资源")
    //@PreAuthorize("@auth.permission('plugin:netdisk:queryByUserId')")
    public Result<PageUtils> listByUserId(@RequestParam(value = "userId", required = false) String userId,
                                          @RequestParam(value = "curPage", required = false, defaultValue = "1") Integer curPage,
                                          @RequestParam(value = "pageSize", required = false, defaultValue = "20") Integer pageSize) {
        if (StringUtils.isBlank(userId)) {
            User user = userService.getByUsername(AuthUtils.getCurrentUsername());
            userId = user.getUserId();
        }
        FileUser fileUser = fileUserService.getFileUserBySysUserId(userId);
        String fileStorageId = fileUser.getFileStorageId();
        Wrapper<FileFolder> wrapper = Wrappers.<FileFolder>lambdaQuery().eq(FileFolder::getParentFolderId, fileStorageId);
        FileFolder fileFolder = fileFolderService.getOne(wrapper);
        String fileFolderId = fileFolder.getId();
        PageUtils pages = listFiles(fileStorageId, fileFolderId, curPage, pageSize);
        return success(pages);
    }


    /**
     * 列表
     */
    @GetMapping
    @ApiOperation("后台列出网盘资源")
    //@PreAuthorize("@auth.permission('plugin:netdisk:query')")
    public Result<PageUtils> list(
            @RequestParam(value = "fileStorageId", required = false) String fileStorageId,
            @RequestParam(value = "fileFolderId", required = false) String fileFolderId,
            @RequestParam(value = "curPage", required = false, defaultValue = "1") Integer curPage,
            @RequestParam(value = "pageSize", required = false, defaultValue = "20") Integer pageSize) {
        PageUtils pages = listFiles(fileStorageId, fileFolderId, curPage, pageSize);
        return success(pages);
    }

    //
    //
    ///**
    // * 上传临时文件
    // *
    // * @param file
    // * @param url
    // * @return
    // */
    //@PostMapping("/uploadTempFile")
    ////@RequiresPermissions("netdisk:upload:tempfile")
    //public String uploadTempFile(@RequestParam("file") MultipartFile file, String url) {
    //    String name = file.getOriginalFilename().replaceAll(" ", "");
    //
    //    if (!FileUtil.verifyName(name)) {
    //        logger.error("临时文件上传失败!文件名不符合规范...");
    //        session.setAttribute("msg", "上传失败!文件名不符合规范");
    //        return "redirect:temp-file";
    //    }
    //
    //    String path = "temp/" + LocalDateTimeUtil.format() + "/" + UUID.randomUUID();
    //    try {
    //        /**上传成功*/
    //        if (FtpUtil.uploadFile("/" + path, name, file.getInputStream())) {
    //            //logger.info("临时文件上传成功!" + name);
    //            String size = String.valueOf(file.getSize());
    //            //创建临时文件
    //            UploadFile tempFile = UploadFile.builder().name(name).path(path).size(Integer.valueOf(size)).createTime(LocalDateTime.now()).build();
    //            //保存临时文件
    //            if (uploadFileService.save(tempFile)) {
    //                try {
    //
    //                    String fileUUID = UUIDUtils.generateUUID(10);
    //                    String p = request.getSession().getServletContext().getRealPath("/user_img/");
    //                    //Long t = tempFile.getUploadTime().toInstant(ZoneOffset.of("+8")).toEpochMilli();
    //                    url = url + "/file/share?t=" + fileUUID + "&f=" + tempFile.getId() + "&p=" + size + "&flag=2";
    //                    File targetFile = new File(p, "");
    //                    if (!targetFile.exists()) {
    //                        targetFile.mkdirs();
    //                    }
    //
    //                    File f = new File(p, fileUUID + ".jpg");
    //                    if (!f.exists()) {
    //                        //文件不存在,开始生成二维码并保存文件
    //                        OutputStream os = new FileOutputStream(f);
    //                        QRCodeUtil.encode(url, "/static/img/logo.png", os, true);
    //                        os.close();
    //                    }
    //
    //                    //异步删除临时文件
    //                    //这里暂且用着spring提供的定时任务吧
    //                    uploadFileService.asyncRemoveById(tempFile.getId());
    //                    session.setAttribute("imgPath", "user_img/" + fileUUID + ".jpg");
    //                    session.setAttribute("url", url);
    //                    session.setAttribute("msg", "上传成功，扫码/访问链接 即可下载！");
    //                    return "redirect:temp-file";
    //                } catch (Exception e) {
    //                    e.printStackTrace();
    //                }
    //            } else {
    //                logger.info("临时文件数据库写入失败!" + name);
    //                session.setAttribute("url", "error");
    //                session.setAttribute("msg", "服务器出错了，临时文件上传失败!");
    //            }
    //        } else {
    //            logger.info("临时文件上传失败!" + name);
    //            session.setAttribute("url", "error");
    //            session.setAttribute("msg", "服务器出错了，上传失败!");
    //        }
    //    } catch (IOException e) {
    //        e.printStackTrace();
    //    }
    //    return "redirect:/temp-file";
    //}

    @PostMapping("/uploadFile")

    //@RequiresPermissions("netdisk:upload:file")
    //@RequestParam 可以用于从query parameters, form data, 和parts in multipart requests中获取参数。
    //post是没有query parameters的,这里也不是form提交, 不过这里有multipart requests

    public Result<String> uploadFile(@RequestParam("file") MultipartFile file) {

        String fileStorageId = request.getHeader("fileStorageId");
        String fileFolderId = request.getHeader("fileFolderId");
        String fileUserId = request.getHeader("fileUserId");
        System.out.println("收到的请求");
        System.out.println("fileStorageId: " + fileStorageId);
        System.out.println("fileFolderId: " + fileFolderId);
        System.out.println("fileUserId: " + fileUserId);
        if (fileUserId != null) {
            fileUser = fileUserService.getById(fileUserId);
        }
        System.out.println(fileUser);
        return netdiskService.uploadFile(file, fileUserId, fileStorageId, fileFolderId, request);
//        /**选择一个指定用户、且用户有权上传下载，可用的文件仓库*/
//        FileStorage fileStorage = fileStorageService.getFileStorageByFileUserId(fileUser.getId(), fileStorageId);
//        if (fileStorage == null) {
//            return failure(MISSING_PERMISSION, "用户没有上传文件的权限!上传失败...");
//        }
//
//        String uploadFileName = file.getOriginalFilename().replaceAll(" ", ""); //不接受文件有空格
//        System.out.println("filename:" + uploadFileName);
//        /**获取当前目录下所有文件，判断是否已存在*/
//        List<UploadFile> uploadFiles = null;
//        if (isRootDir(fileFolderId)) {
//            uploadFiles = uploadFileService.getRootFilesByFileStorageId(fileStorageId);
//        } else {
//            uploadFiles = uploadFileService.getFilesByParentFolderId(fileFolderId);
//        }
//        /**校验MD5，判断数据重复*/
//        String uploadFileMD5 = FileUtil.generateFileMD5(file);
//        boolean fileMd5Exist = uploadFiles.stream().anyMatch(f -> f.getMd5().equals(uploadFileMD5));
//
//        if (fileMd5Exist) {
//            return failure(CONFLICT, "当前文件已存在!上传失败...");
//        }
//        /**数据不重复时候处理文件名重复*/
//        uploadFileName = FileUtil.autoRenameExistFileName(uploadFiles.stream().map(UploadFile::getName).collect(Collectors.toList()), uploadFileName);
//
//        if (!FileUtil.verifyName(uploadFileName)) {
//            return failure("上传失败!文件名不符合规范...");
//        }
//
//        Integer uploadFileByteSize = Math.toIntExact(file.getSize() / 1024); //2047T空间可存放
//        /**判断仓库容量*/
//        if (fileStorage.getCurrentSize() + uploadFileByteSize > fileStorage.getMaxSize()) {
//            return failure("上传失败!仓库已满。");
//        }
//
//        //处理文件大小
//        String byteSizeStr = String.valueOf(file.getSize() / 1024.0);
//        int indexDot = byteSizeStr.lastIndexOf(".");
//        byteSizeStr = byteSizeStr.substring(0, indexDot); //只要前面的字节数字 - 整型
//        Integer byteSize = Integer.valueOf(byteSizeStr);
//        //获取文件后缀
//        int index = uploadFileName.lastIndexOf(".");
//        String fileNameSuffix = "";
//        int type = 4;
//
//        if (existSuffix(index)) {
//            fileNameSuffix = uploadFileName.substring(index).toLowerCase(); //.开始拦截 .doc .html
//            uploadFileName = uploadFileName.substring(0, index);
//            //获得文件类型数字
//            type = FileUtil.getFileType(fileNameSuffix); //判断大概的文件类型 如果不符合就是other类型
//        } else {
//            fileNameSuffix = ""; //无后缀情况
//        }
//
//        System.out.println("上传时候的文件名：" + uploadFileName);
//        try {
//            //todo 用户多仓库的时候 就不能这样放了 不过其实也行 莫名之中就知道文件上传者在这仓库所有文件了
//            String path = fileStorage.getId() + "/" + fileUser.getId() + "/" + fileFolderId; //文件相对路径: [文件仓库id]/[系统用户id]/[文件夹id]
//            boolean uploadSuccess = FtpUtil.uploadFile("/" + path, uploadFileName + fileNameSuffix, file.getInputStream());
//            if (uploadSuccess) {
//                /**存储文件、调整容量*/
//                UploadFile uploadFile = UploadFile.builder()
//                        .name(uploadFileName).UUID(UUIDUtils.generateUUID()).md5(uploadFileMD5).fileStorageId(fileUser.getFileStorageId()).path(path)
//                        .downloadCount(0).createTime(LocalDateTime.now()).parentFolderId(fileFolderId)
//                        .size(byteSize).type(type).suffix(fileNameSuffix).build();
//                uploadFileService.save(uploadFile);
//                System.out.println(request.getContextPath());
//                System.out.println(request.getContextPath());
//                return R.data(getFileUrl(uploadFile, request.getContextPath()));
//            } else {
//                return failure("文件上传失败!" + file.getOriginalFilename());
//            }
//        } catch (IOException e) {
//            e.printStackTrace();
//        }
//        return R.ok();
    }

    @PostMapping("/uploadFileByUserId")
    public Result<String> uploadFileByUserId(@RequestParam("file") MultipartFile file) {

        String userId = request.getHeader("userId");
        System.out.println("收到的请求");
        if (userId == null) {
            return failure();
        }
        fileUser = fileUserService.getFileUserBySysUserId(userId);
        String fileStorageId = fileUser.getFileStorageId();
        Wrapper<FileFolder> wrapper = Wrappers.<FileFolder>lambdaQuery().eq(FileFolder::getFileStorageId, fileStorageId);
        FileFolder fileFolder = fileFolderService.getOne(wrapper);
        String fileFolderId = fileFolder.getId();
        System.out.println(fileUser);
        return netdiskService.uploadFile(file, fileUser.getId(), fileStorageId, fileFolderId, request);
    }

    @GetMapping("/downloadFile")
    @ApiOperation("后台下载文件接口")
    //@RequiresPermissions("netdisk:download:file")
    public void downloadFile(@RequestParam String fileId, @RequestParam String fileStorageId, @RequestParam String fileUserId) {
//        String fileStorageId = Long.valueOf(request.getHeader("fileStorageId"));
        //Long folderId = Long.valueOf(request.getHeader("folderId"));
        if (fileUserId == null) {
            fileUserId = fileUser.getId();
        }
        netdiskService.downloadFile(fileUserId, fileStorageId, fileId, request, response);
//        List<FileStorage> fileStorages = fileStorageService.getFileStoragesByPermission(fileUserId, 3);
//        if (CollectionUtil.isEmpty(fileStorages)) {
//            logger.error("用户没有可用的文件仓库");
////            return "redirect:/error401Page";
//        }
//        System.out.println(fileStorages);
//        System.out.println(fileId);
//        System.out.println(fileStorageId);
//        Optional<FileStorage> fileStorageOptional = fileStorages.stream().filter(fs -> fs.getId().equals(fileStorageId)).findFirst();
//        if (!fileStorageOptional.isPresent()) {
//            logger.error("用户没有下载文件的权限!下载失败...");
////            return "redirect:/error401Page";
//        }
//        UploadFile uploadFile = uploadFileService.getById(fileId);
//        if (uploadFile == null) {
//            logger.error("下载的文件不存在!下载失败...");
////            return "redirect:/error404Page";
//        }
//
//        try {
//            downloadFile(uploadFile);
//        } catch (Exception e) {
////            return "fail";
//        }
//        return "success";
    }

    @GetMapping("/deleteFile")
    @ApiOperation("FTP中删除文件 - json")
    //@RequiresPermissions("netdisk:delete:file")
    public Result<Boolean> deleteFile(@RequestParam("fileId") String fileId) {
        return success(netdiskService.deleteFile(fileId));
    }

    @PostMapping("/deleteFileFolder")
    @ApiOperation("FTP中删除文件夹 - json")
    //@RequiresPermissions("netdisk:delete:folder")
    public Result<String> deleteFileFolder(@RequestBody FileFolder fileFolder) {
        System.out.println("aaa:" + fileFolder.getId());
        FileFolder folder = fileFolderService.getById(fileFolder.getId());
        deleteFileFolderRecursively(folder);
        return success();
        //return folder.getParentFolderId() == 0 ? "redirect:/files" : "redirect:/files?fileFolderId=" + folder.getParentFolderId();
    }

    @PostMapping("/delete")
    @ApiOperation("判断删除文件还是文件夹")
    //@RequiresPermissions("netdisk:delete:folder")
    public Result<String> deleteFileOrFileFolder(@RequestParam("id") String id) {
        UploadFile uploadFile = uploadFileService.getById(id);
        if (uploadFile != null) {
            netdiskService.deleteFile(id);
        } else {
            FileFolder folder = fileFolderService.getById(id);
            if (folder != null) {
                deleteFileFolderRecursively(folder);
            }
        }
        return success();
    }

    @PostMapping("/rename")
    @ApiOperation("判断更名文件还是文件夹")
    //@RequiresPermissions("netdisk:delete:folder")
    public Result<String> renameFileOrFileFolder(@RequestParam("id") String id, @RequestParam("name") String name) {
        UploadFile uploadFile = uploadFileService.getById(id);
        if (uploadFile != null) {
            String oldName = uploadFile.getName();
            String newName = name;
            if (!oldName.equals(newName)) {
                boolean b = FtpUtil.reNameFile(uploadFile.getPath() + "/" + uploadFile.getFullName(), uploadFile.getPath() + "/" + newName + uploadFile.getSuffix());
                if (b) {
                    boolean saveFileSuccess = uploadFileService.updateById(UploadFile.builder().id(uploadFile.getId()).name(newName).build());
                    if (saveFileSuccess) {
                        //logger.info("修改文件名成功!原文件名:" + oldName + "  新文件名:" + newName);
                        return success("重命名文件名成功!");
                    } else {
                        return failure("重命名文件名失败!");
                        //logger.error("修改文件名失败!原文件名:" + oldName + "  新文件名:" + newName);
                    }
                }
            }
        } else {
            FileFolder folder = fileFolderService.getById(id);
            if (folder != null) {
                List<FileFolder> fileFolders = fileFolderService.getFileFoldersByParentFolderId(folder.getParentFolderId());
                Optional<FileFolder> FileFolderOptional = fileFolders.stream().filter(fd -> fd.getName().equals(name) && !fd.getId().equals(folder.getId())).findFirst();
                System.out.println("newFileFolder:" + name);
                if (FileFolderOptional.isPresent()) {
                    return failure("添加文件夹失败!文件夹已存在...");
//            return "redirect:/files?error=1&fileFolderId=" + fileFolder.getParentFolderId();
                }
                FileFolder newFileFolder = new FileFolder();
                BeanUtils.copyProperties(folder, newFileFolder);
                newFileFolder.setName(name);
                boolean saveFolderSuccess = fileFolderService.saveOrUpdate(newFileFolder);
                if (saveFolderSuccess) {
                    return failure("重命名文件夹成功!");
//            return "redirect:/files?fileFolderId=" + fileFolder.getParentFolderId();
                }
            }
        }
        return success();
    }

    //todo 可以抽象为N级递归删除接口
    public void deleteFileFolderRecursively(FileFolder folder) {
        List<FileFolder> folders = fileFolderService.getFileFoldersByParentFolderId(folder.getId()); //获取当前目录下所有目录
        List<UploadFile> files = uploadFileService.getFilesByParentFolderId(folder.getId()); //获取当前目录下所有文件
        if (existFiles(files)) {
            files.stream().filter(file -> FtpUtil.deleteFile("/" + file.getPath(), file.getFullName()))
                    .forEach(file -> {
                        uploadFileService.asyncRemoveById(file.getId());
                        fileStorageService.removeFileStorageSize(file.getFileStorageId(), file.getSize());
                    });
//            for (int i = 0; i < files.size(); i++) {
//                String fileId = files.get(i).getId();
//                boolean deletedSuccess = FtpUtil.deleteFile("/" + files.get(i).getPath(), files.get(i).getFullName());
//                if (deletedSuccess) {
//                    uploadFileService.removeById(fileId);
//                    fileStorageService.removeFileStorageSize(folder.getFileStorageId(), Integer.valueOf(files.get(i).getSize()));
//                }
//            }
        }
        if (existFiles(folders)) {
            folders.stream().forEach(f -> deleteFileFolderRecursively(f));
        }
        fileFolderService.removeById(folder.getId());
    }

    @PostMapping("/addFileFolder")
    //@RequiresPermissions("netdisk:add:filefolder")
    public Result<FileFolder> addFolder(@RequestBody FileFolder fileFolder) {
        String fileStorageId = fileFolder.getFileStorageId(); //所在仓库
        String fileParentFolderId = fileFolder.getParentFolderId(); //所在目录
        String newFileFolderName = fileFolder.getName(); //新目录名字

        System.out.println(fileStorageId);
        System.out.println(fileParentFolderId);
        System.out.println(newFileFolderName);

        FileFolder fileParentFolder = fileFolderService.getById(fileParentFolderId);
        if (fileParentFolder == null) {
            throw new BusinessException("找不到父目录");
        }
        String urlState = "fileFolderId=" + fileParentFolderId + "&fileStorageId=" + fileStorageId;
        List<FileFolder> fileFolders = fileFolderService.getFileFoldersByParentFolderId(fileParentFolderId);
        Optional<FileFolder> FileFolderOptional = fileFolders.stream().filter(fd -> fd.getName().equals(newFileFolderName)).findFirst();

        if (FileFolderOptional.isPresent()) {
//            throw new BusinessException("已存在相同目录名", CONFLICT);
//            logger.info("添加文件夹失败!文件夹已存在...");
//            return "redirect:/files?error=1&" + urlState;
            return failure("添加文件夹失败!文件夹已存在...");
        }
        FileFolder newFileFolder = FileFolder.builder().id(IDUtils.uuid()).fileStorageId(fileStorageId).parentFolderId(fileParentFolderId).name(newFileFolderName).gmtCreated(TimeUtil.getNowTimeToSeconds()).build();

        boolean saveFolderSuccess = fileFolderService.save(newFileFolder);
        if (saveFolderSuccess) {
//            logger.info("添加文件夹成功!" + newFileFolder.getName());
//            return "redirect:/files?" + urlState;
            return success(ApiEnum.ADD_SUCCESS, newFileFolder);
        }
//        logger.info("添加文件夹失败! 保存出现问题!");
//        return "redirect:/files?error=1&" + urlState;
        return failure("添加文件夹失败! 保存出现问题!");
    }


    @PostMapping("/updateFolder")
    @ApiOperation("更新文件夹")
    //@RequiresPermissions("netdisk:update:filefolder")
    public Result<String> updateFolder(@RequestBody FileFolder newFileFolder) {
        FileFolder fileFolder = fileFolderService.getById(newFileFolder.getId());
        List<FileFolder> fileFolders = fileFolderService.getFileFoldersByParentFolderId(fileFolder.getParentFolderId());
        Optional<FileFolder> FileFolderOptional = fileFolders.stream().filter(fd -> fd.getName().equals(newFileFolder.getName()) && !fd.getId().equals(fileFolder.getId())).findFirst();
        System.out.println("newFileFolder:" + newFileFolder);
        if (FileFolderOptional.isPresent()) {
            return failure("添加文件夹失败!文件夹已存在...");
//            return "redirect:/files?error=1&fileFolderId=" + fileFolder.getParentFolderId();
        }
        boolean saveFolderSuccess = fileFolderService.saveOrUpdate(newFileFolder);
        if (saveFolderSuccess) {
            return failure("重命名文件夹成功!");
//            return "redirect:/files?fileFolderId=" + fileFolder.getParentFolderId();
        }
//        logger.info("添加文件夹失败! 保存出现问题!");
        return failure("添加文件夹失败! 保存出现问题!");
//        return "redirect:/files?error=1&fileFolderId=" + fileFolder.getParentFolderId();
    }

    @PostMapping("/updateFileName")
    @ApiOperation("修改文件名字")
    //@RequiresPermissions("netdisk:update:file")
    public Result<String> updateFileName(@RequestBody UploadFile file) {
        UploadFile uploadFile = uploadFileService.getById(file.getId());
        if (uploadFile != null) {
            String oldName = uploadFile.getName();
            String newName = file.getName();
            if (!oldName.equals(newName)) {
                boolean b = FtpUtil.reNameFile(uploadFile.getPath() + "/" + uploadFile.getFullName(), uploadFile.getPath() + "/" + newName + uploadFile.getSuffix());
                if (b) {
                    boolean saveFileSuccess = uploadFileService.updateById(UploadFile.builder().id(uploadFile.getId()).name(newName).build());
                    if (saveFileSuccess) {
                        //logger.info("修改文件名成功!原文件名:" + oldName + "  新文件名:" + newName);
                        return success("重命名文件名成功!");
                    } else {
                        return failure("重命名文件名失败!");
                        //logger.error("修改文件名失败!原文件名:" + oldName + "  新文件名:" + newName);
                    }
                }
            }
        }
        return failure("重命名文件名失败!");
//        return "redirect:/files?fileFolderId=" + uploadFile.getParentFolderId() + "&fileUserId=" + fileUserId;
    }


    /**
     * 分享链接的下载功能
     *
     * @param fileId
     * @param uuid
     */
    @GetMapping("/file")
    public void file(@RequestParam("f") String fileId, @RequestParam("t") String uuid) {
        if (fileId == null || uuid == null) {
            return;
        }
        UploadFile uploadFile = uploadFileService.getById(fileId);
        if (uploadFile == null) {
            return;
        }
        if (!uuid.equals(uploadFile.getUUID())) {
            return;
        }
        try {
            downloadFile(uploadFile);
        } catch (Exception e) {
            return;
        }
        return;
    }

    @GetMapping("/getqrcode")
    @ApiOperation("获取文件下载二维码")
    //@RequiresPermissions("netdisk:qrcode:get")
    public Result<Map<String, Object>> getQrCode(@RequestParam("fileId") String fileId, @RequestParam("url") String url) {
        Map<String, Object> map = new HashMap<>();
        if (fileId != null) {
            UploadFile file = uploadFileService.getById(fileId);
            if (file != null) {
                try {
                    String UUID = IDUtils.uuid();
                    String fileUUID = file.getUUID();
                    //String path = request.getSession().getServletContext().getRealPath("/user_img/");

                    url = url + "/file/share?t=" + UUID + "&t2=" + fileUUID + "&f=" + file.getId() + "&flag=1";
                    System.out.println("URL:" + url);
                    File targetFile = Paths.get("res/", "user_img").toFile();
                    if (!targetFile.exists()) {
                        targetFile.mkdirs();
                    }
                    File f = new File(targetFile.getPath(), fileId + ".jpg");
                    if (!f.exists()) {
                        OutputStream os = new FileOutputStream(f);
                        QRCodeUtil.encode(url, "/static/img/logo.png", os, true);
                        os.close();
                    }
                    map.put("imgPath", "user_img/" + fileId + ".jpg");
                    map.put("url", url);
                    //4小时缓存
                    redisTemplate.opsForValue().set(UUID, String.valueOf(file.getId()), fileExpiredTime, TimeUnit.SECONDS);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return success(map);
    }


    @GetMapping("/file/share")
    @ApiOperation("二维码/URL分享下载功能")
    //@RequiresPermissions("netdisk:share:file")
    public Result<String> shareFile(@RequestParam("f") String fileId, @RequestParam("t") String uuid, @RequestParam("t2") String fileUUID) {

        if (fileId == null || uuid == null) {
            //logger.info("下载分享文件失败，参数错误");
            return failure("下载分享文件失败，参数错误");
        }
        System.out.println("AAA:" + uuid);
        boolean hasKeyUUID = redisTemplate.hasKey(uuid);
        System.out.println(hasKeyUUID);
        String redisFileId = null;
        if (hasKeyUUID) {
            redisFileId = redisTemplate.opsForValue().get(uuid);

            //logger.info("从缓存中获取了fileid = " + redisFileId);
            //logger.info("fileid = " + fileId);
            if (!redisFileId.equals(fileId)) {
                //logger.info("下载分享文件失败，参数不一致");
                return failure("下载分享文件失败，参数不一致");

            }
        }
        if (redisFileId == null) {
            return failure("redis缓存不存在");
        }
        UploadFile uploadFile = uploadFileService.getById(redisFileId);
        if (uploadFile == null) {
            //logger.info("查找文件失败");
            return failure("查找文件失败");
        }
        //        url = url + "/file/share?t=" + UUIDUtils.generateUUID(10) + "&f=" + file.getId() + "&p=" + file.getSize() + "&flag=1";
        if (!fileUUID.equals(uploadFile.getUUID())) {
            //logger.info("下载分享文件失败，传入UUID与文件存储UUID不一致");
            return failure("下载分享文件失败，传入UUID与文件存储UUID不一致");
        }

        try {
            downloadFile(uploadFile);
        } catch (Exception e) {
            return failure();

        }
        return success();
    }

    @GetMapping("/getFileByFileId")
    public Result<UploadFile> getFileByFileId(@RequestParam("fileId") String fileId) {
        UploadFile uploadFile = uploadFileService.getById(fileId);
        try {
            return success(uploadFile);
        } catch (Exception e) {
            return failure();
        }
    }

    @GetMapping("/downloadById")
    public void download(@RequestParam("fileId") String fileId) {
        UploadFile uploadFile = uploadFileService.getById(fileId);
        if (uploadFile == null) {
            //logger.error("下载的文件不存在!下载失败...");
//            return failure();
        }
        try {
            downloadFile(uploadFile);
        } catch (Exception e) {

//            return failure();
        }
    }

    @GetMapping("/download")
    @ApiOperation("直接下载文件")
    //@RequiresPermissions("netdisk:download")
    public void download(@RequestParam("fileId") String fileId, @RequestParam("fileUserId") String fileUserId) {
        if (fileId == null) {
            System.out.println("缺少文件id");
//            return failure();
        }
        if (fileUserId == null) {
            System.out.println("缺少文件用户id");
//            return failure();
        }
        UploadFile uploadFile = uploadFileService.getById(fileId);
        if (uploadFile == null) {
            //logger.error("下载的文件不存在!下载失败...");
//            return failure();
        }
        List<FileStorage> fileStorage = fileStorageService.getFileStoragesByPermission(fileUserId, 2); //1仅上传 2可下载 3可下载可上传
        if (!fileStorage.contains(uploadFile.getFileStorageId())) {
            //logger.error("没有下载权限!下载失败...");
//            return failure();
        }
        //logger.error("开始下载文件");
        try {
            downloadFile(uploadFile);
        } catch (Exception e) {

//            return failure();
        }

//        return R.ok();
    }


    public boolean downloadFile(UploadFile uploadFile) throws Exception {
        String id = uploadFile.getId();
        String remotePath = uploadFile.getPath();
        String fileNameTemp = uploadFile.getFullName();
        Integer times = uploadFile.getDownloadCount();
        boolean downloadSuccess = false;
        OutputStream os = null;
        System.out.println("测试测试");
        try {
            os = new BufferedOutputStream(response.getOutputStream());
            //解决下载文件时 中文文件名乱码问题
            boolean isMSIE = BrowserUtil.isMSBrowser(request);
//
            if (isMSIE) {
                fileNameTemp = URLEncoder.encode(fileNameTemp, "UTF-8");
                System.out.println("isMSIE" + fileNameTemp);
            } else {
                fileNameTemp = new String(fileNameTemp.getBytes("UTF-8"), "UTF-8");
                System.out.println("notMSIE" + fileNameTemp);
            }
            System.out.println("fileNameTemp:" + fileNameTemp);
            // 设置正确编码的文件名
            response.setCharacterEncoding("utf-8");
            response.setContentType("multipart/form-data");
            // 修复纯文本下载直接显式在response问题

            //String mimeType = Files.probeContentType(Path.of("/" + remotePath));
            //System.out.println("mimeType"+mimeType);
            //
            //if (mimeType != null && mimeType.startsWith("text")) {
            //    // 是文本文件
            //    System.out.println("是文本文件");
            //    response.setContentType("text/plain");
            //} else {
            //    response.setContentType("application/octet-stream");
            //}

            response.setHeader("Content-Disposition", "attachment;fileName=" + URLEncoder.encode(fileNameTemp, "UTF-8"));
            //logger.info("测试下载");
            //uploadFile.getFullName()
            // 处理下载次数
            if (FtpUtil.downloadFile("/" + remotePath, uploadFile.getUUID() + uploadFile.getSuffix(), os)) { // /remotePath/uploadFile.name 无后缀 为文件所在目录
                downloadSuccess = uploadFileService.saveOrUpdate(
                        UploadFile.builder().id(id).downloadCount(times + 1).build());
                //logger.info("文件下载成功!");
            }
            os.flush();
            os.close();
        } finally {
            try {
                os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return downloadSuccess;
    }

    @GetMapping("/getNetdisk")
    @ApiOperation("获取文件用户、文件仓库、文件根目录数据")
    public Result<Map<String, Object>> getNetdisk(@RequestParam("userId") String userId) {
        Map<String, Object> map = new HashMap<>();

        if (StringUtils.isBlank(userId)) {
            User user = userService.getByUsername(AuthUtils.getCurrentUsername());
            userId = user.getUserId();
        }

        FileUser fileUser = fileUserService.getFileUserBySysUserId(userId);
        String fileStorageId = fileUser.getFileStorageId();
        Wrapper<FileFolder> wrapper = Wrappers.<FileFolder>lambdaQuery().eq(FileFolder::getParentFolderId, fileStorageId);
        FileFolder fileFolder = fileFolderService.getOne(wrapper);

        map.put("fileUserId", fileUser.getId());
        map.put("fileFolderId", fileFolder.getId());
        map.put("fileStorageId", fileStorageId);

        return success(map);
    }

    @PostMapping("/createService")
    @ApiOperation("创建服务口")
    //@RequiresPermissions("netdisk:caller:create")
    public Result<Boolean> createService(@NotNull String name, @NotNull String serviceId) {
        return success(netdiskService.createService(name, serviceId));
    }


    @RequestMapping(value = "/image/{fileStorageId}/{fileUserId}/{fileFolderId}/{fileId}", method = RequestMethod.GET)
    public void getImage(@PathVariable("fileUserId") String fileUserId, @PathVariable("fileStorageId") String fileStorageId, @PathVariable("fileFolderId") String fileFolderId, @PathVariable("fileId") String fileId, HttpServletResponse response) throws IOException {
        String imagePath = fileStorageId + "/" + fileUserId + "/" + fileFolderId;
        UploadFile uploadFile = uploadFileService.getById(fileId);
        File imageFile = new File("E:\\毕业设计\\springboot-plugin-framework-example-master\\res\\" + imagePath +"/"+ uploadFile.getFullUUIDName());
        FileInputStream fileInputStream = new FileInputStream(imageFile);
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len;
        while ((len = fileInputStream.read(buffer)) != -1) {
            outputStream.write(buffer, 0, len);
        }
        byte[] data = outputStream.toByteArray();
        response.setContentType("image/png"); // 设置响应类型为图片
        ServletOutputStream out = response.getOutputStream();
        out.write(data);
        out.flush();
        out.close();
        //byte[] imageBytes = new byte[(int) imageFile.length()];
        //fileInputStream.read(imageBytes);
        //fileInputStream.close();
        //String encodedImage = Base64.getEncoder().encodeToString(imageBytes);
        //String imageSrc = "data:image/png;base64," + encodedImage;
        //System.out.println(imageSrc);
        //return imageSrc;
        //return IOUtils.toByteArray(fileInputStream);
    }

}

